﻿using System;
using System.Configuration;
using System.Linq;
using NLog;

namespace Jet.VersionIncrementor
{
	internal static class Program
	{
		private static readonly Logger _logger = LogManager.GetCurrentClassLogger();

		private static void ValidateConfiguration(VersionConfigurationSection section)
		{
		    if (section.RetrieveSolutionVersion)
		    {
                if (section.IncrementedComponent != VersionComponent.None
                    || !String.IsNullOrEmpty(section.Version))
                {
                    throw new ConfigurationErrorsException("Cannot retrieve and assign version at the same time!");
                }
            }

		    if (section.IncrementedComponent != VersionComponent.None)
		    {
		        if (section.RetrieveSolutionVersion || !String.IsNullOrEmpty(section.Version))
		        {
                    throw new ConfigurationErrorsException("Only version component or version can be assigned");
                }
		    }

		    if (!String.IsNullOrEmpty(section.Version))
		    {
                if (section.RetrieveSolutionVersion || section.IncrementedComponent != VersionComponent.None)
                {
                    throw new ConfigurationErrorsException("Only version component or version can be assigned");
                }
            }

			if (section.IncrementedComponent == VersionComponent.None && String.IsNullOrEmpty(section.Version) && !section.RetrieveSolutionVersion)
			{
				throw new ConfigurationErrorsException("Version component or version or retrieving must be assigned");
			}
			_logger.Debug("Configuration validated");
		}

		private static string IncrementVersion(VersionComponent incrementedValue, BaseProjectParser projectParser)
		{
			_logger.Debug("Incrementing '{0}' value for project '{1}'", incrementedValue, projectParser.ProjectFileName);
			var version = projectParser.CurrentVersion;
			switch (incrementedValue)
			{
				case VersionComponent.Major:
					projectParser.CurrentVersion = new Version(version.Major + 1, version.Minor, version.Build, version.Revision);
					break;
				case VersionComponent.Minor:
					projectParser.CurrentVersion = new Version(version.Major, version.Minor + 1, version.Build, version.Revision);
					break;
				case VersionComponent.Build:
					projectParser.CurrentVersion = new Version(version.Major, version.Minor, version.Build + 1, version.Revision);
					break;
				case VersionComponent.Revision:
					projectParser.CurrentVersion = new Version(version.Major, version.Minor, version.Build, version.Revision + 1);
					break;
			}
			return version.ToString();
		}

	    private static void RetrieveSolutionVersion(SolutionParser parser)
	    {
	        var result = from project in parser.Projects
	            select project.CurrentVersion;
	        foreach (var version in result.Distinct())
	        {
	            Console.WriteLine(version);
	        }
	    }

		private static int Main()
		{
			try
			{
				var cfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
				var section = (VersionConfigurationSection)cfg.GetSection("VersionIncrementor");
				ValidateConfiguration(section);
				_logger.Debug("Processing solution '{0}'", section.SolutionPath);

                var solutionParser = new SolutionParser(section.SolutionPath);
                if (section.RetrieveSolutionVersion)
                {
                    RetrieveSolutionVersion(solutionParser);
                    return 0;
                }
                var version = String.Empty;
				foreach (var projectParser in solutionParser.Projects)
				{
					_logger.Info("Processing project '{0}'", projectParser.ProjectFileName);
					if (section.IncrementedComponent != VersionComponent.None)
					{
						version = IncrementVersion(section.IncrementedComponent, projectParser);
					}
					else
					{
						_logger.Debug("Setting new version '{0}' for project '{1}'", solutionParser, projectParser.ProjectFileName);
						projectParser.CurrentVersion = new Version(section.Version);
						version = section.Version;
					}
				}
				if (!String.IsNullOrEmpty(section.VersionGlobalVariable))
				{
					Environment.SetEnvironmentVariable(section.VersionGlobalVariable, version, EnvironmentVariableTarget.Machine);
				}
			}
			catch (Exception e)
			{
				_logger.FatalException("Fatal Exception", e);
				return 1;
			}
			return 0;
		}
	}
}
